/*
 * Personaje.cpp
 *
 *  Created on: 01/09/2012
 *      Author: rodrigo
 */

#include "Personaje.h"
#define TIEMPO_NACIMIENTO 4000

#include <algorithm>
#define FPS 20
#define LAPSUS_ANIMACIONES 1000/FPS
#define CANT_VIDAS_INICIAL 3
#define TIEMPO_INVENCIBILIDAD 10000
#define TIEMPO_VOLADOR 7000

using namespace std;
#include <iostream>

const int EstadoPersonaje::Muriendo = 0;
const int EstadoPersonaje::SinParticular = 1;
const int EstadoPersonaje::SubiendoEscalera = 2;
const int EstadoPersonaje::AgarrandoEstrellaInvencibilidad = 3;
const int EstadoPersonaje::Volando = 4;
const int EstadoPersonaje::Gano = 5;
const int EstadoPersonaje::Perdio = 6;
const vector<int> EstadoPersonaje::acciones = make_vector<int>() << EstadoBasico::Movimiento << EstadoBasico::Saltando;
const vector<string> EstadoPersonaje::descripcionAcciones = make_vector<string>() << "caminar" << "saltar";
const vector<int> EstadoPersonaje::animaciones = make_vector<int>() << EstadoBasico::Quieto << EstadoBasico::Animando;
const vector<int> EstadoPersonaje::accionesParticulares = make_vector<int>() << EstadoPersonaje::Muriendo;
const vector<string> EstadoPersonaje::descripcionAccionesParticulares = make_vector<string>() << "morir";

const int SonidosPersonaje::Colision = 0;
const int SonidosPersonaje::Salto = 1;
const int SonidosPersonaje::Invencibilidad = 2;
const int SonidosPersonaje::ColisionObstaculo = 3;
const int SonidosPersonaje::RescatePrincesa = 4;
const int SonidosPersonaje::Size = 5;
const vector<string> SonidosPersonaje::descripcionSonidos = make_vector<string>() << "colision" << "salto" << "invencibilidad" << "colision_obstaculo" << "rescatar_princesa";

Personaje::Personaje(int x, int y, int maximoX, int maximoY, string nombre) : ObjetoMovible(x, y, maximoX, maximoY){
	
	vidas = CANT_VIDAS_INICIAL;
	tiempoNacimiento = 0;
	
	estadoArriba = SinMovimiento;
	estadoAbajo = SinMovimiento;
	
	alturaEscalera = 0;
	armadura = false;
	invencibilidad.first = false;
	volatil.first = false;
	puntaje = 0;
	
	activo = false;
	titilar = true;

	estadoParticular = EstadoPersonaje::SinParticular;
	estadoBonus = EstadoPersonaje::SinParticular;
	estadoVida = Naciendo;
	
	for (int i=0; i<SonidosPersonaje::Size; i++)
		sonidos.push_back(pair< pair<int, int> , bool>(pair<int, int>(0, MUSICA_EVENTO), false));
	sonidos.at(SonidosPersonaje::Invencibilidad).first.second = MUSICA_FONDO;
	
	tipo = PERSONAJE;
	this->nombre = nombre;
}

Personaje::~Personaje() {
	// TODO Auto-generated destructor stub
}

void Personaje::setAlturaMaximaRelativa() {
	
	alturaMaximaRelativa = (getSalto()*getSalto()) / (gravedad*2);
}

void Personaje::setAlturaMaximaReal() {
	
	alturaMaximaReal = getY() - alturaMaximaRelativa;
}

void Personaje::setArmadura(bool estado) {
	armadura = estado;
}

void Personaje::setInvencibilidad(bool estado) {
	
	if (estado && !invencibilidad.first) {
		estadoBonus = EstadoPersonaje::AgarrandoEstrellaInvencibilidad;
	}
	invencibilidad.first = estado;
}

void Personaje::setVolatil(bool estado) {

	if (!estado && volatil.first) {
		volatil.second = 0;
		if (estadoBonus == EstadoPersonaje::Volando)
			estadoBonus = EstadoPersonaje::SinParticular;
			setEstado(EstadoBasico::Saltando);
	}
	
	volatil.first = estado;
}

int Personaje::getVidas() {
	return vidas;
}

int Personaje::getEstadoParticular() {
	return estadoParticular;
}
	
bool Personaje::getArmadura() {
	return armadura;
}

bool Personaje::getVolatil() {
	return volatil.first;
}

bool Personaje::getInvencibilidad() {
	return invencibilidad.first;
}

int Personaje::getPuntaje() {
	return puntaje;
}

void Personaje::SumarPuntos(int puntos) {
	puntaje += puntos;
}

void Personaje::RestarPuntos(int puntos) {
	puntaje -= puntos;
}

void Personaje::Saltar() {
	if(estado != EstadoBasico::Saltando) StartSonido(SonidosPersonaje::Salto);
	ObjetoMovible::Saltar();
}

void Personaje::setAlturaEscalera(int altura) {
	
	if (altura > alturaEscalera)
		alturaEscalera = altura;
}

int Personaje::getAlturaEscalera() {
	
	return alturaEscalera;
}

void Personaje::setEstado(int estado) {
	
	if (estado == EstadoBasico::Saltando && this->estado != EstadoBasico::Saltando)
		setAlturaMaximaReal();
		
	ObjetoMovible::setEstado(estado);
}

void Personaje::restarVida() {
	if(getPiso() < getY() + getAlto()){
		setEstadoVida(Muriendo);
		if (vidas > 0) this->vidas--;
		setActivo(false);
		setArmadura(false);
		setInvencibilidad(false);
	}else if (!getInvencibilidad()) {
		
		if (!getArmadura()) {
			
			setEstadoVida(Muriendo);
			if (vidas > 0) this->vidas--;
			setActivo(false);
		}
		else {
			setArmadura(false);
		}
	}
}

void Personaje::aumentarVida() {
	this->vidas++;
}

void Personaje::Morir() {
	restarVida();
}

void Personaje::setEstadoParticular(int estadoParticular) {
	
	this->estadoParticular = estadoParticular;
}

EstadoMovimiento* Personaje::getDirEstadoArriba() {
	
	return &estadoArriba;
}

EstadoMovimiento* Personaje::getDirEstadoAbajo() {
	
	return &estadoAbajo;
}

void Personaje::setMargenScroll(int margen){
	this->margenScroll=margen;
}

int Personaje::getMargenScroll(){
	return this->margenScroll;
}

string Personaje::getNombre() {
	return nombre;
}

void Personaje::setIdSonido(int idSonido, int sonido) {
	sonidos.at(sonido).first.first = idSonido;
}

void Personaje::StartSonido(int sonido) {
	sonidos.at(sonido).second = true;
}

void Personaje::StopSonido(int sonido) {
	sonidos.at(sonido).second = false;
}

void Personaje::MoverArriba(Uint32 deltaTime) {

	setPosicion(getX(), getY() - velocidad*deltaTime/1000);
	
	if (estado != EstadoBasico::Movimiento && estado != EstadoBasico::Saltando) {
		setEstado(EstadoBasico::Movimiento);
	}
}

void Personaje::MoverAbajo(int maximoY, Uint32 deltaTime) {

	setPosicion(getX(), getY() + velocidad*deltaTime/1000);
	
	if (estado != EstadoBasico::Movimiento && estado != EstadoBasico::Saltando) {
		setEstado(EstadoBasico::Movimiento);
	}
}

void Personaje::caer(Uint32 deltaTime, int maximoY) {
	
	if (estadoParticular == EstadoPersonaje::SubiendoEscalera) return;
	if (estadoBonus == EstadoPersonaje::Volando && estadoSalto == Moviendo) return;

	if (estadoBonus == EstadoPersonaje::Volando && estadoSalto != Moviendo) {
		estadoBonus = EstadoPersonaje::SinParticular;
		setEstado(EstadoBasico::Saltando);
	}
		
	double viejaVelocidad = getVelocidadY();
	ObjetoMovible::caer(deltaTime, maximoY);
	double nuevaVelocidad = getVelocidadY();
	
	if (getVolatil() && estadoSalto == Moviendo) {
		if (estadoParticular == EstadoBasico::Saltando) {
			if (viejaVelocidad >= 0 && nuevaVelocidad <= 0) {
				//setPosicion(getX(), alturaMaximaReal - getAlto());
				//setVelocidadY(0);
				estadoBonus = EstadoPersonaje::Volando;
				setEstado(EstadoBasico::Quieto);
			}
		}
	}
}

void Personaje::addAccionParticular(int idImagen, int cuadros) {
	Animacion *animacion = new Animacion (cuadros, 0, idImagen, ancho, alto);
    accionesParticulares.push_back(animacion);
}

pair<idImagen_t, int> Personaje::getDibujable(Uint32 time) {
	
	pair<idImagen_t, int> dibujable;
	
	if (getEstadoVida() != Muriendo) {				
		dibujable = ObjetoMovible::getDibujable(time);
	}
	else {
		bool status = true;
		dibujable = getDibujableParticular(accionesParticulares.at(EstadoPersonaje::Muriendo), time, &status, 2*LAPSUS_ANIMACIONES);
		if (!status) {
			if (getVidas() > 0) {
				setEstadoVida(Naciendo);
				setPosicion(posicionInicial.getX(), posicionInicial.getY());
				setOrientacion(Derecha);
				tiempoNacimiento = 0;
			}
			else setEstadoVida(Muerto);
		}
	}
	
	return dibujable;
}

pair<idImagen_t, int> Personaje::getDibujable(Uint32 time, vector<ObjetoEstatico*> v_estaticos, vector<Obstaculo*> v_obstaculos, vector<ObjetoMovible*> v_movibles, ObjetoEstatico* princesa, vector<ObjetoMovible*> v_personajes) {
	
	for (int i=0; i<SonidosPersonaje::Size; i++) {
		StopSonido(i);
	}
	
	pair<idImagen_t, int> dibujable = ObjetoMovible::getDibujable(time, v_estaticos, v_obstaculos, v_movibles, princesa, v_personajes);
	
	if (getEstadoVida() == Naciendo && titilar) {
		dibujable = pair<idImagen_t, int>(SIN_IMAGEN, 0);
	}
	
	titilar = (titilar) ? false : true;
	return dibujable;
}

void Personaje::Actualizar(Uint32 time) {

	if (getInvencibilidad()) StartSonido(SonidosPersonaje::Invencibilidad);
	
	if (getEstadoVida() == Naciendo) {
		if (tiempoNacimiento == 0) tiempoNacimiento = time;
		if (time - tiempoNacimiento > TIEMPO_NACIMIENTO) {
			setActivo(true);
			setEstadoVida(Vivo);
		}
	}

	if (estadoDerecha == Moviendo) {
		MoverDerecha(maximoX, time - lastTimeActualizar);
		if (getX() + ancho > maximoX) {
			setPosicion(maximoX - ancho, getY());
			Frenar();
		}
	}
	
	if (estadoDerecha == Empezo) {
		estadoDerecha = Moviendo;
	}
	
	if (estadoIzquierda == Moviendo) {
		MoverIzquierda(time - lastTimeActualizar);
		if (getX() < 0) {
			setPosicion(0, getY());
			Frenar();
		}
	}
	
	if (estadoArriba == Moviendo) {
		if (estadoParticular == EstadoPersonaje::SubiendoEscalera) {
			MoverArriba(time - lastTimeActualizar);
			if (getY() + alto < alturaEscalera) {
				setPosicion(getX(), alturaEscalera - alto);
			}
		}
	}
	
	if (estadoArriba == Empezo) {
		estadoArriba = Moviendo;
	}
	
	if (estadoAbajo == Moviendo) {
		if (estadoParticular == EstadoPersonaje::SubiendoEscalera) {
			MoverAbajo(maximoY, time - lastTimeActualizar);
			if (getPosicion().getY() + getAlto() > getPiso()) {
				setPosicion(getPosicion().getX(), getPiso() - getAlto());
			}
		}
	}
	
	if (estadoAbajo == Empezo) {
		estadoAbajo = Moviendo;
	}
	
	if (estadoIzquierda == Empezo) {
		estadoIzquierda = Moviendo;
	}
	
	if (estadoSalto == Empezo) {
		Saltar();
		estadoSalto = Moviendo;
	}
	
	if ( estadoDerecha != Moviendo && estadoIzquierda != Moviendo &&
			estadoArriba != Moviendo && estadoAbajo != Moviendo) {
		Frenar();
		estadoDerecha = SinMovimiento;
		estadoIzquierda = SinMovimiento;
		estadoArriba = SinMovimiento;
		estadoAbajo = SinMovimiento;
	}
	
	if (estadoBonus == EstadoPersonaje::AgarrandoEstrellaInvencibilidad) {
		invencibilidad.second = time;
		estadoBonus = EstadoPersonaje::SinParticular;
	}
	
	if (getVolatil() && volatil.second == 0) {
		volatil.second = time;
	}
	
	if (getVolatil() && time - volatil.second >= TIEMPO_VOLADOR) {
		setVolatil(false);
	}
	
	if (getInvencibilidad() && time - invencibilidad.second >= TIEMPO_INVENCIBILIDAD) {
		setInvencibilidad(false);
	}
	
	if (estadoParticular == EstadoPersonaje::SubiendoEscalera) {
		estadoParticular = EstadoPersonaje::SinParticular;
		alturaEscalera = 0;
	}
}

vector< pair<int, int> > Personaje::getSonidos() {
	
	vector< pair<int, int> > sonidos;
	for (int i=0; i<SonidosPersonaje::Size; i++) {
		if (this->sonidos.at(i).second)
			sonidos.push_back(this->sonidos.at(i).first);
	}
	
	return sonidos;
}

int Personaje::indexEstado(int estado) {
	
	vector<int> estados = EstadoPersonaje::acciones;
	unsigned int posicion = find(estados.begin(), estados.end(), estado) - estados.begin();
	
	if (posicion < estados.size())
		return posicion;
		
	estados = EstadoPersonaje::animaciones;
	posicion = find(estados.begin(), estados.end(), estado) - estados.begin();
	
	if (posicion < estados.size())
		return posicion;
		
	return -1;
}

void Personaje::Ganar() {
	
	setEstadoParticular(EstadoPersonaje::Gano);
}

void Personaje::Perder() {
	
	setEstadoParticular(EstadoPersonaje::Perdio);
}

bool Personaje::Gano() {
	
	return (estadoParticular == EstadoPersonaje::Gano);
}

Punto Personaje::getPosicionInicial() {
	return posicionInicial;
}
void Personaje::setPosicionInicial(int x, int y) {
	
	Punto posicion(x, y);
	posicionInicial = posicion;
}
